﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

namespace Dot5Demo.MarkDowngm
{
    public class MDGrid
    {
        public Alignment Alignment { get; private set; }

        public MDGrid()
        {
            ColumnRow = new MDGridColumnRow();
            Rows = new List<MDGridDataRow>();
        }

        public MDGridColumnRow ColumnRow { get; private set; }
        public List<MDGridDataRow> Rows { get; private set; }
        public MDGridDataRow NewRow()
        {
            return new MDGridDataRow(ColumnRow);
        }

        public void AddCol(MDGridColumn column)
        {
            ColumnRow.Add(column);
            ClearCache();
        }

        public void AddCol(string headerText)
        {
            MDGridColumn col = new MDGridColumn()
            {
                Text = headerText,
                Alignment = Alignment,
            };
            AddCol(col);
        }

        public void SetAlignment(Alignment alignment)
        {
            if (Alignment == alignment)
                return;
            Alignment = alignment;
            ColumnRow.UpdateAligenment(alignment);
            ClearCache();
        }

        public void AddRow(MDGridDataRow row)
        {
            Rows.Add(row); ;
            row.SetColRow(ColumnRow);
            ClearCache();
        }
        private StringBuilder _builer;
        public void ClearCache()
        {
            _builer = null;
        }
        public string GenerateStr()
        {
            if (_builer != null)
                return _builer.ToString();
            var builer = new StringBuilder();
            builer.Append(ColumnRow.GenerateString());
            foreach (var item in Rows)
            {
                builer.Append(item.GenerateString());
            }
            _builer = builer;
            return _builer.ToString();
        }
    }

    public class MDGridColumnRow : ICollection<MDGridColumn>
    {
        public event EventHandler<ColumnChangedEventArgs> ColumnChanged;

        public MDGridColumnRow()
        {
            Columns = new List<MDGridColumn>();
        }

        public List<MDGridColumn> Columns { get; set; }
        public int Count
        { get { return Columns.Count; } }

        public bool IsReadOnly { get; set; }

        public void Add(MDGridColumn item)
        {
            Columns.Add(item);
            ClearCache();
            ColumnChanged?.Invoke(this, new ColumnChangedEventArgs(MarkDowngm.ColumnChanged.Added, item));
        }

        public void Clear()
        {
            Columns.Clear();
            ClearCache();
            ColumnChanged?.Invoke(this, new ColumnChangedEventArgs(MarkDowngm.ColumnChanged.Cleared));
        }

        public bool Contains(MDGridColumn item)
        {
            return Columns.Contains(item);
        }

        public void CopyTo(MDGridColumn[] array, int arrayIndex)
        {
            Columns.CopyTo(array, arrayIndex);
        }

        public IEnumerator<MDGridColumn> GetEnumerator()
        {
            return Columns.GetEnumerator();
        }

        public bool Remove(MDGridColumn item)
        {
            int ind = Columns.IndexOf(item);
            var b = Columns.Remove(item);
            ClearCache();
            ColumnChanged?.Invoke(this, new ColumnChangedEventArgs(MarkDowngm.ColumnChanged.Removed, new int[] { ind }, item));
            return b;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Columns.GetEnumerator();
        }

        public void UpdateAligenment(Alignment alignment)
        {
            Columns.ForEach(c => c.Alignment = alignment);
            ClearCache();
        }

        private StringBuilder _builder;

        public void ClearCache()
        {
            _builder = null;
        }

        public string GenerateString()
        {
            if (_builder != null)
                return _builder.ToString();
            var builder = new StringBuilder();
            builder.Append('|');
            for (int i = 0; i < Columns.Count; i++)
            {
                builder.Append(Columns[i].GenerateStr());
                builder.Append('|');
            }
            builder.Append('\n');
            builder.Append('|');
            for (int i = 0; i < Columns.Count; i++)
            {
                builder.Append(Columns[i].GenerateSymbolStr());
                builder.Append('|');
            }
            builder.Append('\n');
            _builder = builder;
            return builder.ToString();
        }
    }

    public class MDGridDataRow : ICollection<MDGridDataCell>
    {
        private MDGridColumnRow ColRow { get; set; }

        public MDGridDataCell this[int index]
        {
            get { return Cells[index]; }
            set { Cells[index] = value; }
        }

        public void SetColRow(MDGridColumnRow colRow)
        {
            if (ColRow != null)
                colRow.ColumnChanged -= ColRow_ColumnChanged;
            ColRow = colRow;
            colRow.ColumnChanged += ColRow_ColumnChanged;
        }

        public MDGridDataRow(MDGridColumnRow colRow)
        {
            Cells = new List<MDGridDataCell>();
            SetColRow(colRow);
            foreach (var item in colRow)
            {
                Cells.Add(new MDGridDataCell());
            }
        }

        private void ColRow_ColumnChanged(object sender, ColumnChangedEventArgs e)
        {
            switch (e.Changed)
            {
                case ColumnChanged.Added:
                    if (e.Data != null)
                    {
                        for (int i = 0; i < e.Data.Count; i++)
                        {
                            Cells.Add(new MDGridDataCell());
                        }
                    }
                    break;
                case ColumnChanged.Removed:
                    if (e.Indexes != null)
                    {
                        for (int i = 0; i < e.Indexes.Count; i++)
                        {
                            Cells.RemoveAt(e.Indexes[i]);
                        }
                    }
                    break;
                case ColumnChanged.Cleared:
                    Cells.Clear();
                    break;
                default:
                    break;
            }
        }

        public MDGridDataRow()
        {
            Cells = new List<MDGridDataCell>();
        }

        public List<MDGridDataCell> Cells { get; set; }
        public int Count
        {
            get { return Cells.Count; }
        }

        public bool IsReadOnly { get; set; }

        public void Add(MDGridDataCell item)
        {
            Cells.Add(item);
        }

        public void Clear()
        {
            Cells.Clear();
        }

        public bool Contains(MDGridDataCell item)
        {
            return Cells.Contains(item);
        }

        public void CopyTo(MDGridDataCell[] array, int arrayIndex)
        {
            Cells.CopyTo(array, arrayIndex);
        }

        public IEnumerator<MDGridDataCell> GetEnumerator()
        {
            return Cells.GetEnumerator();
        }

        public bool Remove(MDGridDataCell item)
        {
            return Cells.Remove(item);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Cells.GetEnumerator();
        }

        private StringBuilder _builder;

        public void ClearCache()
        {
            _builder = null;
        }

        public string GenerateString()
        {
            if (_builder != null)
                return _builder.ToString();
            var builder = new StringBuilder();
            builder.Append('|');
            for (int i = 0; i < Cells.Count; i++)
            {
                builder.Append(Cells[i].GenerateStr());
                builder.Append('|');
            }
            builder.Append('\n');
            _builder = builder;
            return builder.ToString();
        }
    }

    public abstract class MDGridCell : MDElement
    {
        //public string Text { get; set; }
        //public bool IsBold { get; set; }
        //public bool IsMathFormula { get; set; }
        //public bool UseColor { get; set; }
        //private Color _collor = Color.Black;
        //public Color Color { get; set; }
        //protected string _cachedString;

        //public void ClearCache()
        //{
        //    _cachedString = null;
        //}

        //public virtual string GenerateStr()
        //{
        //    if (_cachedString != null)
        //        return _cachedString;
        //    var str = Text;
        //    if (IsMathFormula)
        //    {
        //        if (Text.Contains("\n"))
        //            str = string.Format("$${0}$$", str);
        //        else
        //            str = string.Format("${0}$", str);
        //    }
        //    if (IsBold)
        //        str = string.Format("*{0}*", str);
        //    if (UseColor)
        //    {
        //        var htmlColorStr = string.Format("#{0:X2}{1:X2}{2:X2}", Color.R, Color.G, Color.B);
        //        str = string.Format("<font color={0}>{1}</font>", htmlColorStr, str);
        //    }
        //    _cachedString = str;
        //    return str;
        //}
    }

    public class MDGridDataCell : MDGridCell
    {
        public MDGridDataCell()
        {
        }
    }

    public class MDGridColumn : MDGridCell
    {
        public Alignment Alignment { get; set; }

        public string GenerateSymbolStr()
        {
            var str = "-----";
            switch (Alignment)
            {
                case Alignment.Left:
                    str = ":" + str;
                    break;

                case Alignment.Right:
                    str = str + ":";
                    break;

                case Alignment.Center:
                default:
                    str = ":" + str + ":";
                    break;
            }
            return str;
        }
    }

    public class ColumnChangedEventArgs : EventArgs
    {
        public ColumnChangedEventArgs(ColumnChanged changed, List<MDGridColumn> data, List<int> indexes)
        {
            Changed = changed;
            Data = data;
            Indexes = indexes;
        }
        public ColumnChangedEventArgs(ColumnChanged changed, List<MDGridColumn> data)
        {
            Changed = changed;
            Data = data;
        }
        public ColumnChangedEventArgs(ColumnChanged changed, params MDGridColumn[] data)
        {
            Changed = changed;
            if (data.Length > 0)
            {
                Data = new List<MDGridColumn>();
                for (int i = 0; i < data.Length; i++)
                {
                    Data.Add(data[i]);
                }
            }
        }
        public ColumnChangedEventArgs(ColumnChanged changed, int[] indexes, params MDGridColumn[] data)
        {
            Changed = changed;
            if (data.Length > 0)
            {
                Data = new List<MDGridColumn>();
                Indexes = new List<int>();
                for (int i = 0; i < data.Length; i++)
                {
                    Data.Add(data[i]);
                    Indexes.Add(indexes[i]);
                }
            }
        }

        public ColumnChangedEventArgs(ColumnChanged changed)
        {
            Changed = changed;
        }

        public ColumnChanged Changed { get; private set; }
        public List<MDGridColumn> Data { get; private set; }
        public List<int> Indexes { get; private set; }
    }

    public enum ColumnChanged
    {
        Added = 0,
        Removed = 1,
        Cleared = 2,
    }
}